package com.app.manage.moudles.push.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.json.JSONUtil;
import com.app.manage.components.CommonComponent;
import com.app.manage.moudles.app.dao.TAppDao;
import com.app.manage.moudles.app.entity.TApp;
import com.app.manage.moudles.confs.constants.GroupEnums;
import com.app.manage.moudles.confs.dao.TGroupRelationDao;
import com.app.manage.moudles.push.constants.TaskStepEnums;
import com.app.manage.moudles.push.dao.TCornTaskDao;
import com.app.manage.moudles.push.dao.TPushTaskAppDao;
import com.app.manage.moudles.push.dao.TPushUploadDao;
import com.app.manage.moudles.push.entity.TCornTask;
import com.app.manage.moudles.push.entity.TPushTaskApp;
import com.app.manage.moudles.push.entity.TPushUpload;
import com.app.manage.moudles.push.pojo.TaskSearchPojo;
import com.app.manage.moudles.push.service.TCornTaskService;
import com.app.manage.moudles.server.dao.TServerDao;
import com.app.manage.moudles.server.entity.TServer;
import com.app.manage.moudles.system.dao.TLogDao;
import com.app.manage.utils.EmptyIPage;
import com.app.manage.utils.SFTPUtil;
import com.app.manage.utils.SshUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.app.manage.moudles.push.dao.TPushTaskDao;
import com.app.manage.moudles.push.entity.TPushTask;
import com.app.manage.moudles.push.service.TPushTaskService;
import io.swagger.models.auth.In;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.io.File;
import java.util.*;
import java.util.stream.Collectors;

/**
 * (TPushTask)表服务实现类
 *
 * @author makejava
 * @since 2025-05-28 10:07:55
 */
@Service("tPushTaskService")
@Slf4j
public class TPushTaskServiceImpl extends ServiceImpl<TPushTaskDao, TPushTask> implements TPushTaskService {



    @Resource
    private TPushTaskAppDao pushTaskAppDao;

    @Resource
    private TPushUploadDao pushUploadDao;

    @Resource
    private TGroupRelationDao groupRelationDao;

    @Resource
    private CommonComponent commonComponent;

    @Resource
    private TCornTaskService tCornTaskService;

    @Resource
    private TCornTaskDao cornTaskDao;

    @Resource
    private TServerDao serverDao;

    @Resource
    private TAppDao appDao;


    @Override
    public IPage<TPushTask> pageData(Integer pageNum, Integer pageSize, TaskSearchPojo task) {
        //查询其他数据
        List<Integer> taskIdList = new ArrayList<>();
        if(task.getLongGroup() != null || StringUtils.isNotEmpty(task.getServerIp()) || StringUtils.isNotEmpty(task.getAppName())){
            //分组
            List<Integer> appIdList = new ArrayList<>();
            if(task.getLongGroup() != null){
                appIdList = groupRelationDao.selectRelationIds(task.getLongGroup(), GroupEnums.APP_GROUP.getType());
                if(CollectionUtils.isEmpty(appIdList)){
                    return new EmptyIPage();
                }
            }
            LambdaUpdateWrapper<TPushTaskApp> query = new LambdaUpdateWrapper<>();
            query.in(!CollectionUtils.isEmpty(appIdList),TPushTaskApp::getAppId,appIdList);
            query.like(StringUtils.isNotEmpty(task.getServerIp()),TPushTaskApp::getServerIp,task.getServerIp());
            query.like(StringUtils.isNotEmpty(task.getAppName()),TPushTaskApp::getAppName,task.getAppName());
            List<TPushTaskApp> taskAppList = pushTaskAppDao.selectList(query);
            if(CollectionUtils.isEmpty(taskAppList)){
                return new EmptyIPage();
            }
            taskIdList = taskAppList.stream().map(TPushTaskApp::getTaskId).collect(Collectors.toList());
            taskIdList = taskIdList.stream().distinct().collect(Collectors.toList());
        }


        //分页查询数据
        LambdaQueryWrapper<TPushTask> query = new LambdaQueryWrapper<>();
        query.like(StringUtils.isNotEmpty(task.getTaskName()),TPushTask::getTaskName,task.getTaskName());
        query.in(!CollectionUtils.isEmpty(taskIdList),TPushTask::getId,taskIdList);
        IPage<TPushTask> retPage = page(Page.of(pageNum,pageSize),query);
        retPage.getRecords().forEach(o->{
            o.setOptCmd(TaskStepEnums.openStepOpt(o.getPushStep()));
            o.setPushStepName(TaskStepEnums.getNameByStep(o.getPushStep()));
        });
        return retPage;
    }

    @Override
    public TPushTask findById(Integer taskId) {
        TPushTask tPushTask = getById(taskId);

        List<Integer> appIdList = new ArrayList<>();
        for (String s : tPushTask.getAppServerIds().split(",")){
            appIdList.add(Integer.parseInt(s));
        }
        tPushTask.setAppServers(appIdList);
        return tPushTask;
    }

    @Override
    public TPushTask buildNewTask() {
        String basicPath = commonComponent.findAppUploadPath(new Date());
        Integer id = 0;

        //查询最大的Id
        TPushTask task = getOne(new LambdaQueryWrapper<TPushTask>()
                .orderByDesc(TPushTask::getId)
                .last("limit 1")
        );
        if(task != null){
            id = task.getId()+1;
        }

        //存储路径
        if(!basicPath.endsWith(File.separator)){
            basicPath += File.separator;
        }
        basicPath = basicPath + "batch_"+id+File.separator;
//        //-----判断存储路径是否存在
//        if(!FileUtil.exist(basicPath)){
//            FileUtil.mkdir(basicPath);
//        }
        //构建基础路径
        TPushTask newTask = new TPushTask();
        newTask.setId(id);
        newTask.setBasicPath(basicPath);
        newTask.setPushStep(0);
        save(newTask);

        //添加日志
        commonComponent.addTaskLog("添加一个新的任务","任务Id:"+id,id);

        return newTask;
    }

    @Override
    public TPushTaskApp saveTask(TPushTask tPushTask) {
        //更新基础信息
        tPushTask.setAppServerIds(tPushTask.getAppServers().stream()
                .map(String::valueOf) // 将每个整数转换为字符串
                .collect(Collectors.joining(",")));
        updateById(tPushTask);
        //更新任务实例
        LambdaUpdateWrapper<TPushTaskApp>  actQuery = new LambdaUpdateWrapper<>();
        actQuery.set(TPushTaskApp::getPushActive,1);
        actQuery.in(TPushTaskApp::getId, Arrays.asList(tPushTask.getTaskAppIds().split(",")));
        pushTaskAppDao.update(null,actQuery);
        actQuery.clear();
        actQuery.set(TPushTaskApp::getPushActive,0);
        actQuery.set(TPushTaskApp::getTaskId,tPushTask.getId());
        actQuery.notIn(TPushTaskApp::getId, Arrays.asList(tPushTask.getTaskAppIds().split(",")));
        pushTaskAppDao.update(null,actQuery);

        if(tPushTask.getPushStep() == 1){
            tCornTaskService.addTask(tPushTask.getId(),tPushTask.getPushTime(),o-> runTask(tPushTask),true);
        }

        //添加任务
        String logName = tPushTask.getPushStep() == 1?"发布任务":"保存任务";
        commonComponent.addTaskLog(logName,"任务Id:"+tPushTask.getId(),tPushTask.getId());

        return null;
    }

    @Override
    public String removeOld(Integer taskId) {
        TPushTask tPushTask = getById(taskId);
        if(tPushTask == null){
            return "当前任务已经删除！";
        }
        if(tPushTask.getPushStep() - TaskStepEnums.step_0.getStep() != 0){
            return "当前任务不可删除！";
        }
        //删除任务
        removeById(taskId);
        //删除实例
        pushTaskAppDao.delete(new LambdaQueryWrapper<TPushTaskApp>().eq(TPushTaskApp::getTaskId,taskId));
        //删除文件
        pushUploadDao.delete(new LambdaQueryWrapper<TPushUpload>().eq(TPushUpload::getTaskId,taskId));
        FileUtil.del(tPushTask.getBasicPath());

        //清除日志
        commonComponent.removeTaskLog(taskId);

        return null;
    }

    @Override
    public void loadTaskToTimer()throws Exception {
        LambdaUpdateWrapper<TCornTask> query = new LambdaUpdateWrapper<>();
        query.gt(TCornTask::getRunDate,new Date());
        List<TCornTask> list = cornTaskDao.selectList(query);
        if(CollectionUtils.isEmpty(list)){
            return;
        }
        List<Integer> taskIdList = list.stream().map(TCornTask::getTaskId).collect(Collectors.toList());
        List<TPushTask> taskLit = list(new LambdaQueryWrapper<TPushTask>().in(TPushTask::getId,taskIdList));
        for(TPushTask t : taskLit){
            tCornTaskService.addTask(t.getId(),t.getPushTime(),o-> runTask(t ),true);
        }
    }

    @Override
    public String stopTask(Integer taskId) {
        TPushTask task = getById(taskId);
        if(task.getPushStep() - TaskStepEnums.step_99.getStep() == 0){
            return "任务已经结束";
        }

        task.setPushStep(TaskStepEnums.step_Z.getStep());
        updateById(task);

        //定时任务删除
        tCornTaskService.stopTask(taskId);

        commonComponent.addTaskLog("停止任务","任务Id:"+task.getId(),taskId);
        return null;
    }

    @Override
    public String restartTask(Integer taskId) {
        TPushTask task = getById(taskId);
        if(task.getPushTime().getTime() < new Date().getTime()){
            return "当前任务已经过期！";
        }

        if(task.getPushStep() - TaskStepEnums.step_0.getStep() != 0 &&  task.getPushStep()  - TaskStepEnums.step_Z.getStep() != 0){
            return "当前任务运行中!";
        }
        if(task.getPushStep() - TaskStepEnums.step_99.getStep() == 0){
            return "任务已经结束";
        }
        task.setPushStep(TaskStepEnums.step_1.getStep());
        updateById(task);
        tCornTaskService.addTask(taskId,task.getPushTime(),o-> runTask(task),true);

        //添加日志
        commonComponent.addTaskLog("启动任务","任务Id:"+task.getId(),taskId);
        return null;
    }

    /**
     * 执行任务
     * @param task
     * @return
     */
    public String  runTask(TPushTask task){
        try {
            Integer taskId = task.getId();

            //--日志一
            commonComponent.addTaskLog("任务执行","任务Id:"+task.getId(),taskId);
            Thread.sleep(1000*1);

            //找到上传的文件
            List<TPushTaskApp> taskAppList = pushTaskAppDao.selectList(
                    new LambdaQueryWrapper<TPushTaskApp>()
                            .eq(TPushTaskApp::getTaskId,task.getId())
                            .eq(TPushTaskApp::getPushActive,1)
            );
            if(CollectionUtil.isEmpty(taskAppList)){
                log.error("未找到需要发布的应用");
                return "未找到需要发布的应用";
            }
            log.info("{}: 运行的任务信息：{}",task.getId(), JSONUtil.toJsonStr(taskAppList));

            //找到需要上传的服务器
            List<Integer> serverIdList = taskAppList.stream().map(TPushTaskApp::getServerId).collect(Collectors.toList());
            List<TServer> tServerList = serverDao.selectList(
                    new LambdaQueryWrapper<TServer>()
                            .in(TServer::getId,serverIdList)
            );
            tServerList = tServerList.stream().distinct().collect(Collectors.toList());
            if(CollectionUtil.isEmpty(tServerList)){
                log.error("未找到需要发布的应用");
                return "未找到设置的服务器";
            }

            List<TServer> finalTServerList = tServerList;
            Map<Integer,TServer> idServerMap = new HashMap<Integer,TServer>(){{
                finalTServerList.forEach(o->{
                    put(o.getId(),o);
                });
            }};

            log.info("{}：即将执行服务器状态检测并上传服务",task.getId());

            for(TServer t : tServerList){
                Boolean checkRes = SshUtils.checkSshConnect(t.getServerIp(),t.getLoginPort(),t.getLoginUser(),t.getLoginPwd(),10);
                log.info("{}: {}服务器状态检测结果：{}",task.getId(),t.getServerIp(), checkRes);

                //--日志二
                commonComponent.addTaskLog("服务器状态检查："+t.getServerIp(),"检查结果："+(checkRes?"正常":"异常"),taskId);
                Thread.sleep(1000*1);

                if(!checkRes){
                    idServerMap.remove(t.getId());
                }
            }

            log.info("{}：服务状态检测结束，最终上传服务：{}",taskId,idServerMap.values().stream().map(TServer::getServerIp).collect(Collectors.toList()));
            if(CollectionUtil.isEmpty(idServerMap.values())){
                return "未找到合适的运行服务器";
            }

            //查询应用路径
            List<TApp> appList = appDao.selectList(new LambdaQueryWrapper<TApp>()
                    .in(TApp::getId,taskAppList.stream().map(TPushTaskApp::getAppId).collect(Collectors.toList()))
            );
            Map<Integer,String> appCmdMap = new HashMap<Integer,String>(){{
                appList.forEach(o->{
                    put(o.getId(),o.getStartCmd());
                });
            }};



            log.info("{}：开始上传文件",taskId);
            List<String> execResList = new ArrayList<>();
            for(TPushTaskApp t : taskAppList){
                TServer ts = idServerMap.get(t.getServerId());
                if(ts == null){
                    continue;
                }
                log.info("{}上传: 服务器IP：{},上传的jar名称：{}",taskId,t.getServerIp(),t.getAppJarName());
                SFTPUtil sftpUtil = new SFTPUtil();
                try {

                    sftpUtil.connect(ts.getLoginUser(),ts.getServerIp(),ts.getLoginPort(),ts.getLoginPwd());
                    Boolean  res = sftpUtil.isDirExist(t.getUploadPath());
                    log.error("{}：远程路径是否存在：{}",taskId,res);
                    if(!res){
                        sftpUtil.createDir(t.getUploadPath());
                        log.info("{}：创建远程服务目录:{}",taskId,t.getUploadPath());
                    }
                    sftpUtil.upLoadFile(FileUtil.getInputStream(t.getLocalPath()),t.getUploadPath(),t.getAppJarName());


                    //--日志三
                    commonComponent.addTaskLog("上传文件到远程服务器："+t.getServerIp(),
                            "本地路径："+t.getLocalPath()+",远程服务器路径："+t.getUploadPath(),
                            taskId);
                    Thread.sleep(1000*1);



                    //执行启动命令
                    String cmd = "cd " + t.getUploadPath()+" && "+appCmdMap.get(t.getAppId());

                    commonComponent.addTaskLog("开始远程执行："+t.getServerIp(),
                            "执行命令："+cmd,
                            taskId);
                    Thread.sleep(1000*1);

                    String execRes =SshUtils.execForStr(ts.getServerIp(),ts.getLoginPort(),ts.getLoginUser(),ts.getLoginPwd(),
                            cmd);

                    Thread.sleep(1000*1);
                    //--日志四：
                    commonComponent.addTaskLog("远程执行结束："+t.getServerIp(),
                            "执行结果："+execRes,
                            taskId);
                    Thread.sleep(1000*1);

                    execResList.add(t.getServerIp()+":"+execRes);

                }catch (Exception e){
                    e.printStackTrace();
                    sftpUtil.close();
                }
            }

            task.setFinishPushTime(new Date());
            task.setPushStep(TaskStepEnums.step_99.getStep());
            task.setPushRes(String.join(" ; ",execResList));
            updateById(task);

            //-日志无
            commonComponent.addTaskLog("任务执行结束",
                    "执行结果："+String.join(" ; ",execResList),
                    taskId);

            tCornTaskService.stopTask(taskId);
        }catch (Exception e2){
            e2.printStackTrace();
        }
        return null;
    }
}

